package com.yuyou.fn.arrangement.service.impl;

import com.github.wens.mybatisplus.plugins.Page;
import com.yuyou.fn.arrangement.service.IArrangementService;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.common.util.Utils;
import com.yuyou.fn.educational.entity.Campus;
import com.yuyou.fn.educational.entity.ClassLecture;
import com.yuyou.fn.educational.entity.CourseClass;
import com.yuyou.fn.educational.entity.Room;
import com.yuyou.fn.educational.service.ICampusService;
import com.yuyou.fn.educational.service.IClassLectureService;
import com.yuyou.fn.educational.service.ICourseClassService;
import com.yuyou.fn.educational.service.IRoomService;
import com.yuyou.fn.educational.vo.ArrangeClassTimeResultVo;
import com.yuyou.fn.platform.entity.SysUser;
import com.yuyou.fn.tradingservice.entity.PersonLeaseMessage;
import com.yuyou.fn.tradingservice.service.IPersonLeaseMessageService;
import com.yuyou.fn.tradingservice.vo.PersonLeaseQueryVo;
import com.yuyou.fn.tradingservice.vo.TimeStampLong;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

/**
 * Created by Administrator on 2017/9/30.
 */
@Service
public class ArrangementServiceImpl implements IArrangementService{
    @Resource
    private ICampusService campusService;

    @Resource
    private IRoomService roomService;

    @Resource
    private ICourseClassService courseClassService;

    @Resource
    private IClassLectureService classLectureService;

    @Resource
    private IPersonLeaseMessageService personLeaseMessageService;


    @Override
    @Transactional
    public void saveOrUpdateArrangementRoom(Long classId, Long roomId,SysUser sysUser) {
        this.confirmRearrange(classId,2);
        List<Long> roomIds=this.findCanUseRoomIds(roomId,classId,sysUser,null,null);
        if (roomIds==null ||roomIds.size()<=0){
            throw new BusException("所选时间与所选课室冲突，请重新设置");
        }
        courseClassService.saveArrangementRoom(classId, roomId);

        //personLeaseMessageService.deleteByClassIdAndLeaseState(classId,999);
        this.createLease(classId,roomId,sysUser);
    }

    @Override
    public Page<Room> findRoomByBuyOrCreate(Long classId, SysUser sysUser, Long campusId, String roomName, int pageNo, int pageSize) {
        List<Long> realRoomIdList=this.findCanUseRoomIds(null,classId,sysUser,campusId,roomName);
        Page<Room> roomPage=roomService.findByRoomIds(realRoomIdList,pageNo,pageSize);
        return roomPage;
    }

    @Override
    @Transactional
    public void changeStatus(List<Long> classIds, Integer status) {
        courseClassService.changeStatus(classIds,status);
        if (status==2){
            personLeaseMessageService.deleteByClassIdsAndLeaseState(classIds,999);
        }
    }

    @Override
    public List<Long> findCanUseRoomIds(Long checkRoomId,Long classId, SysUser sysUser, Long campusId, String roomName) {
        List<Long> realRoomIdList=new ArrayList<Long>();
        CourseClass courseClass=courseClassService.findById(classId);
        Long busTeamId=courseClass.getBusTeamId();
        Long areaTeamId=courseClass.getAreaTeamId();
        List<ClassLecture> classLectureList=classLectureService.findClassLectureByClassId(classId);
        BitSet bitSet=new BitSet();
        Date minDate=null;
        Date maxDate=null;
        String minStartTime=null;
        String maxEndTime=null;
        if (classLectureList==null || classLectureList.size()<=0){
            throw new BusException("请先排时间");
        }
        for (ClassLecture classLecture:classLectureList){
            String startStr= Utils.formatDate(classLecture.getClassDate(),"yyyy-MM-dd")+" "+classLecture.getStartTime();
            Date startDate=Utils.parseDate(startStr,"yyyy-MM-dd HH:mm");
            String endStr=Utils.formatDate(classLecture.getClassDate(),"yyyy-MM-dd")+" "+classLecture.getEndTime();
            Date endDate=Utils.parseDate(endStr,"yyyy-MM-dd HH:mm");
            bitSet.set(TimeUtils.toMini(startDate),TimeUtils.toMini(endDate));
            if (minDate==null || minDate.getTime()>startDate.getTime()){
                minDate=startDate;
            }
            if (maxDate==null || maxDate.getTime()<endDate.getTime()){
                maxDate=endDate;
            }
            if (minStartTime==null || minStartTime.compareTo(classLecture.getStartTime())>0){
                minStartTime=classLecture.getStartTime();
            }
            if (maxEndTime==null || maxEndTime.compareTo(classLecture.getEndTime())<0){
                maxEndTime=classLecture.getEndTime();
            }

        }
        if (sysUser.getUserType()==1 || sysUser.getUserType()==0){
            List<Long> roomIdList=null;
            List<Room> roomList=null;
            if (checkRoomId!=null){
                roomIdList=new ArrayList<Long>(1);
                roomIdList.add(checkRoomId);
                roomList=roomService.findByIds(roomIdList);
            }else {
                List<Campus> campusList=campusService.findByIdsAndStateAndAreaTeamIds(1, Arrays.asList(areaTeamId));
                List<Long> campusIdList= BeanUtils.toList(campusList,"campusId");
                roomList=roomService.findByCond(campusIdList,campusId,roomName,1);
                roomIdList= BeanUtils.toList(roomList,"roomId");
            }

            if (roomIdList==null || roomIdList.size()<=0){
                return realRoomIdList;
            }
            PersonLeaseQueryVo personLeaseQueryVo=new PersonLeaseQueryVo();
            personLeaseQueryVo.setRoomIds(roomIdList);
            personLeaseQueryVo.setLeaseStates("0,1");
            personLeaseQueryVo.setEndGreateStart(maxDate);
            personLeaseQueryVo.setStartLessEnd(minDate);
            personLeaseQueryVo.setStartTimeLessEndTime(minStartTime);
            personLeaseQueryVo.setEndTimeGreateStartTime(maxEndTime);
            List<PersonLeaseMessage> personLeaseMessageList=personLeaseMessageService.findPersonLeaseMessage(personLeaseQueryVo);
            Map<Long,List<PersonLeaseMessage>> map=BeanUtils.toGroup(personLeaseMessageList,"roomId");
            //Iterator<Map.Entry<Long, List<PersonLeaseMessage>>> entries = map.entrySet().iterator();
            for (Room room:roomList){

                Long roomId=room.getRoomId();

                List<PersonLeaseMessage> roomLeaseList=map.get(roomId);
                if (roomLeaseList==null) {
                    realRoomIdList.add(roomId);
                    continue;
                }
                List<TimeStampLong> allTimeStampLongList=new ArrayList<TimeStampLong>();
                List<String> confictIds=new ArrayList<String>();
                for (PersonLeaseMessage personLeaseMessage:roomLeaseList){
                    if (personLeaseMessage.getPayMainAccountId().equals(busTeamId)){
                        realRoomIdList.add(roomId);
                        continue;
                    }
                    allTimeStampLongList.addAll(personLeaseMessageService.findTimeStampLongByPersonLease(personLeaseMessage));
                    if (StringUtils.isNotEmpty(personLeaseMessage.getConfictIds())){
                        confictIds.add(personLeaseMessage.getConfictIds());
                    }
                }
                BitSet roomBitSet=new BitSet();
                for (TimeStampLong timeStampLong:allTimeStampLongList){
                    roomBitSet.set(timeStampLong.getStartTimeStamp(),timeStampLong.getEndTimeStamp());
                }
                if (confictIds.size()>0){
                    List<TimeStampLong> confictTimeStampLongList=new ArrayList<TimeStampLong>();
                    String str=StringUtils.join(confictIds,",");
                    List<Long> confictIdList=Utils.toLongIds(str);
                    List<PersonLeaseMessage> confictPersonLeaseMessages=personLeaseMessageService.findByIds(confictIdList);
                    for (PersonLeaseMessage personLeaseMessage:confictPersonLeaseMessages){
                        confictTimeStampLongList.addAll(personLeaseMessageService.findTimeStampLongByPersonLease(personLeaseMessage));
                    }
                    for (TimeStampLong timeStampLong:confictTimeStampLongList){
                        roomBitSet.clear(timeStampLong.getStartTimeStamp(),timeStampLong.getEndTimeStamp());
                    }
                }
                if (!bitSet.intersects(roomBitSet)){
                    realRoomIdList.add(roomId);
                }
            }
        }else if (sysUser.getUserType()==2){//业务组
            PersonLeaseQueryVo personLeaseQueryVo=new PersonLeaseQueryVo();
            personLeaseQueryVo.setPayMainAccountId(busTeamId);
            personLeaseQueryVo.setLeaseState(1);
            if (campusId!=null){
                personLeaseQueryVo.setCampusId(campusId);
            }
            if (checkRoomId!=null){
                personLeaseQueryVo.setRoomId(checkRoomId);
            }
            personLeaseQueryVo.setEndGreateStart(maxDate);
            personLeaseQueryVo.setStartLessEnd(minDate);
            personLeaseQueryVo.setStartTimeLessEndTime(minStartTime);
            personLeaseQueryVo.setEndTimeGreateStartTime(maxEndTime);
            List<PersonLeaseMessage> personLeaseMessageList=personLeaseMessageService.findPersonLeaseMessage(personLeaseQueryVo);
            Map<Long,List<PersonLeaseMessage>> map=BeanUtils.toGroup(personLeaseMessageList,"roomId");
            Iterator<Map.Entry<Long, List<PersonLeaseMessage>>> entries = map.entrySet().iterator();
            while (entries.hasNext()){
                Map.Entry<Long, List<PersonLeaseMessage>> entry = entries.next();
                Long roomId=entry.getKey();
                List<PersonLeaseMessage> roomLeaseList=entry.getValue();
                BitSet roomBitSet=new BitSet();
                List<TimeStampLong> timeStampLongList=new ArrayList<TimeStampLong>();
                List<String> confictIds=new ArrayList<String>();
                for (PersonLeaseMessage personLeaseMessage:roomLeaseList){
                    timeStampLongList.addAll(personLeaseMessageService.findTimeStampLongByPersonLease(personLeaseMessage));
                    if (StringUtils.isNotEmpty(personLeaseMessage.getConfictIds())){
                        confictIds.add(personLeaseMessage.getConfictIds());
                    }
                }
                for (TimeStampLong timeStampLong:timeStampLongList){
                    roomBitSet.set(timeStampLong.getStartTimeStamp(),timeStampLong.getEndTimeStamp());
                }
                if (confictIds.size()>0){
                    List<TimeStampLong> confictTimeStampLongList=new ArrayList<TimeStampLong>();
                    String str=StringUtils.join(confictIds,",");
                    List<Long> confictIdList=Utils.toLongIds(str);
                    List<PersonLeaseMessage> confictPersonLeaseMessages=personLeaseMessageService.findByIds(confictIdList);
                    for (PersonLeaseMessage personLeaseMessage:confictPersonLeaseMessages){
                        confictTimeStampLongList.addAll(personLeaseMessageService.findTimeStampLongByPersonLease(personLeaseMessage));
                    }
                    for (TimeStampLong timeStampLong:confictTimeStampLongList){
                        roomBitSet.clear(timeStampLong.getStartTimeStamp(),timeStampLong.getEndTimeStamp());
                    }
                }
                BitSet cloneBitSet=(BitSet) bitSet.clone();
                cloneBitSet.andNot(roomBitSet);
                if (cloneBitSet.cardinality()==0){
                    realRoomIdList.add(roomId);
                }
            }
        }
        /*判断课室改时间是否被排了课*/
        PersonLeaseQueryVo check=new PersonLeaseQueryVo();
        check.setRoomIds(realRoomIdList);
        check.setLeaseState(999);
        check.setEndGreateStart(maxDate);
        check.setStartLessEnd(minDate);
        check.setStartTimeLessEndTime(minStartTime);
        check.setEndTimeGreateStartTime(maxEndTime);
        List<PersonLeaseMessage> personLeaseMessageList=personLeaseMessageService.findPersonLeaseMessage(check);
        Map<Long,List<PersonLeaseMessage>> map=BeanUtils.toGroup(personLeaseMessageList,"roomId");
        Iterator<Long> iterator=realRoomIdList.iterator();
        while (iterator.hasNext()){
            Long roomId=iterator.next();
            List<PersonLeaseMessage> roomLeaseList=map.get(roomId);
            if (roomLeaseList==null || roomLeaseList.size()<=0){
                continue;
            }else {
                BitSet checkBitSet=new BitSet();
                List<TimeStampLong> timeStampLongList=new ArrayList<TimeStampLong>();
                for (PersonLeaseMessage personLeaseMessage:roomLeaseList){
                    timeStampLongList.addAll(personLeaseMessageService.findTimeStampLongByPersonLease(personLeaseMessage));
                }
                for (TimeStampLong timeStampLong:timeStampLongList){
                    checkBitSet.set(timeStampLong.getStartTimeStamp(),timeStampLong.getEndTimeStamp());
                }
                if (bitSet.intersects(checkBitSet)){
                    iterator.remove();
                }
            }
        }
        return  realRoomIdList;
    }

    @Override
    @Transactional
    public void createLease(Long classId, Long roomId,SysUser sysUser) {
       // personLeaseMessageService.deleteByClassIdAndLeaseState(classId,999);
        Room room=roomService.findById(roomId);
        CourseClass courseClass=courseClassService.findById(classId);
        Long payMainAccountId=null;
        if (sysUser.getUserType()==1 || sysUser.getUserType()==0){
            payMainAccountId=courseClass.getAreaTeamId();
        }else{
            payMainAccountId=courseClass.getBusTeamId();
        }

        List<ClassLecture> classLectureList=classLectureService.findClassLectureByClassId(classId);
        Map<String,List<ClassLecture>> map=new HashMap<String,List<ClassLecture>>();
        Date minDate=null;
        Date maxDate=null;
        for (ClassLecture classLecture:classLectureList){
            String time=classLecture.getStartTime()+"-"+classLecture.getEndTime();
            List<ClassLecture> mapList=null;
            if (map.containsKey(time)){
                mapList=map.get(time);
            }else{
                mapList=new ArrayList<ClassLecture>();
            }
            mapList.add(classLecture);
            map.put(time,mapList);
            if (minDate==null || minDate.getTime()>classLecture.getClassDate().getTime()){
                minDate=classLecture.getClassDate();
            }
            if (maxDate==null || maxDate.getTime()<classLecture.getClassDate().getTime()){
                maxDate=classLecture.getClassDate();
            }

        }
        Iterator<Map.Entry<String,List<ClassLecture>>> resultEntries=map.entrySet().iterator();
        List<PersonLeaseMessage> personLeaseMessageList=new ArrayList<PersonLeaseMessage>();
        while(resultEntries.hasNext()){
            Map<Integer,List<Date>> dayMap=new HashMap<Integer, List<Date>>();
            Map.Entry<String,List<ClassLecture>> entry = resultEntries.next();
            String time=entry.getKey();
            List<ClassLecture> classLectures=entry.getValue();
            for (ClassLecture classLecture:classLectures){
                Date date=classLecture.getClassDate();
                Integer weekNum=TimeUtils.getWeekOfDate(date);
                List<Date> dateList=null;
                if (dayMap.containsKey(weekNum)){
                    dateList=dayMap.get(weekNum);
                }else {
                    dateList=new ArrayList<Date>();
                }
                dateList.add(classLecture.getClassDate());
                dayMap.put(weekNum,dateList);
            }
            String[]  times=time.split("-");
            if (dayMap.size()==7 || (classLectureList.size()<7&&classLectureList.size()==dayMap.size())){
                PersonLeaseMessage personLeaseMessage=new PersonLeaseMessage();
                personLeaseMessage.setWeekNum(-1);
                personLeaseMessage.setRoomId(roomId);
                personLeaseMessage.setCampusId(room.getCampusId());
                personLeaseMessage.setStartTime(times[0]);
                personLeaseMessage.setEndTime(times[1]);
                personLeaseMessage.setProductId(0L);
                personLeaseMessage.setLeaseState(999);
                personLeaseMessage.setStart(minDate);
                personLeaseMessage.setEnd(maxDate);
                personLeaseMessage.setClassId(classId);
                personLeaseMessage.setPayMainAccountId(payMainAccountId);
                personLeaseMessage.setCreateTime(TimeUtils.now());
                personLeaseMessage.setUpdateTime(TimeUtils.now());
                personLeaseMessage.setTimeType(-1);
                personLeaseMessageList.add(personLeaseMessage);
                continue;
            }

            Iterator<Map.Entry<Integer,List<Date>>> dayEntries=dayMap.entrySet().iterator();
            while (dayEntries.hasNext()){
                Map.Entry<Integer,List<Date>> dayEntry = dayEntries.next();
                List<Date> dateList=dayEntry.getValue();
                Collections.sort(dateList, new Comparator<Date>() {
                    @Override
                    public int compare(Date o1, Date o2) {
                        return o1.compareTo(o2);
                    }
                });
                Integer weekNum=dayEntry.getKey();
                PersonLeaseMessage personLeaseMessage=new PersonLeaseMessage();
                personLeaseMessage.setClassId(classId);
                personLeaseMessage.setWeekNum(weekNum);
                personLeaseMessage.setRoomId(roomId);
                personLeaseMessage.setCampusId(room.getCampusId());
                personLeaseMessage.setStart(dateList.get(0));
                personLeaseMessage.setEnd(dateList.get(dateList.size()-1));
                personLeaseMessage.setStartTime(times[0]);
                personLeaseMessage.setEndTime(times[1]);
                personLeaseMessage.setProductId(0L);
                personLeaseMessage.setLeaseState(999);
                personLeaseMessage.setCreateTime(TimeUtils.now());
                personLeaseMessage.setUpdateTime(TimeUtils.now());
                personLeaseMessage.setTimeType(-1);
                personLeaseMessage.setPayMainAccountId(payMainAccountId);
                personLeaseMessageList.add(personLeaseMessage);
            }
        }
        if (personLeaseMessageList.size()>0){
            personLeaseMessageService.insertBatch(personLeaseMessageList);
        }
    }

    @Override
    @Transactional
    public void confirmRearrange(Long classId, Integer which) {
        courseClassService.prepareRearrange(classId,which);
        if (which == 2 || which ==1) {
            personLeaseMessageService.deleteByClassIdAndLeaseState(classId, 999);
        }
    }

    @Override
    @Transactional
    public void rearrangeTimeForLecture(Long classLectureId, String date, String time, boolean updateAfterLecture,SysUser sysUser) {
        courseClassService.rearrangeTimeForLecture(classLectureId,date,time,updateAfterLecture);
        ClassLecture classLecture=classLectureService.findById(classLectureId);
        Long classId=classLecture.getClassId();
        CourseClass courseClass=courseClassService.findById(classId);
        if (courseClass.getRoomId()!=null){
            personLeaseMessageService.deleteByClassIdAndLeaseState(classId,999);
            List<Long> roomIdList=this.findCanUseRoomIds(courseClass.getRoomId(),classId,sysUser,null,null);
           /* if (roomIdList==null || !roomIdList.contains(courseClass.getRoomId())){
                throw new BusException("重新更改的时间已被占用。请重新更改时间或更换教室");
            }*/
            if(Utils.checkListNotEmpty(roomIdList)){
                this.createLease(classId,courseClass.getRoomId(),sysUser);
            }

        }
    }

    @Override
    @Transactional
    public void batchAdjustLectures(List<Long> classLectureIds, Date date,boolean updateAfterLecture ,SysUser sysUser) {
        if (Utils.checkListEmpty(classLectureIds)) {
            return;
        }
        List<ClassLecture> classLectureList = classLectureService.findByIdsOrderByNo(classLectureIds);

        Map<Long, List<ClassLecture>> classLectureMap = BeanUtils.toGroup(classLectureList, "classId");

        for (Map.Entry<Long,List<ClassLecture>> entry :classLectureMap.entrySet()){
            List<ClassLecture> oneClassLectureList=entry.getValue();
            if(oneClassLectureList.size()>1){
                throw new BusException("同个班级不允许同时调整两个或以上的讲次！");
            }
        }


        for (ClassLecture classLecture :classLectureList){
            this.rearrangeTimeForLecture(classLecture.getClassLectureId(),Utils.formatDate(date,"yyyy-MM-dd"),classLecture.getStartTime()+"-"+classLecture.getEndTime(),updateAfterLecture,sysUser);
        }


    }

    @Override
    @Transactional
    public void batchAdjustLectureTimes(List<Long> classLectureIds, String time, SysUser sysUser) {
        if (Utils.checkListEmpty(classLectureIds)) {
            return;
        }
        List<ClassLecture> classLectureList = classLectureService.findByIdsOrderByNo(classLectureIds);

        for (ClassLecture classLecture :classLectureList){
            this.rearrangeTimeForLecture(classLecture.getClassLectureId(),Utils.formatDate(classLecture.getClassDate(),"yyyy-MM-dd"),time,false,sysUser);
        }
    }

    @Override
    @Transactional
    public void saveClassChange(Long classId, String className, String studyingTime, Long teacherId,SysUser sysUser) {
        courseClassService.saveClassChange(classId,className,studyingTime,teacherId);
        personLeaseMessageService.deleteByClassIdAndLeaseState(classId,999);
        CourseClass courseClass=courseClassService.findById(classId);
        if (courseClass.getRoomId()!=null){
            personLeaseMessageService.deleteByClassIdAndLeaseState(classId,999);
            List<Long> roomIdList=this.findCanUseRoomIds(courseClass.getRoomId(),classId,sysUser,null,null);
      /*      if (roomIdList==null || !roomIdList.contains(courseClass.getRoomId())){
                throw new BusException("重新更改的时间已被占用。请重新更改时间或更换教室");
            }*/
            if (Utils.checkListNotEmpty(roomIdList)){
                this.createLease(classId,courseClass.getRoomId(),sysUser);
            }

        }
    }

    @Override
    @Transactional
    public void saveArrangeClassTimeResult(Long classId, List<ArrangeClassTimeResultVo> arrangeClassTimeResultList,SysUser sysUser) {
        /*先查出原先的排班数据*/
        List<ClassLecture> classLectureList=classLectureService.findClassLectureByClassId(classId);
        this.confirmRearrange(classId,1);
        courseClassService.saveArrangeClassTimeResult(classId, arrangeClassTimeResultList );
        CourseClass courseClass=courseClassService.findById(classId);
        if(courseClass.getIsArrangeTeacher()==1){
            List<Long> teacherIds=BeanUtils.toList(classLectureList,"teacherId");
            if (teacherIds.size()>0){
                this.saveArrangementTeacher(classId,teacherIds);
            }
        }
        if (courseClass.getIsArrangeRoom()==1 && courseClass.getRoomId()!=null){
            this.saveOrUpdateArrangementRoom(classId,courseClass.getRoomId(),sysUser);
        }
    }

    @Override
    @Transactional
    public void saveArrangementTeacher(Long classId, List<Long> teacherIds) {
        this.confirmRearrange(classId,3);
        courseClassService.saveArrangementTeacher(classId, teacherIds);
    }

    @Override
    public void releaseTeacher(Long classId) {
        this.confirmRearrange(classId,3);
    }

    @Override
    public void releaseRoom(Long classId) {
        this.confirmRearrange(classId,2);
    }
}
